﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Linq.Expressions;

namespace SmartLib.Reflection.Dynamic
{
    /// <summary>
    /// 动态属性
    /// </summary>
    public static class DynamicProperty
    {
        public delegate object GetValueExecutor(object instance);
        public delegate void SetValueExecutor(object instance, object value);

        /// <summary>
        /// 编译设置属性值表达式
        /// </summary>
        /// <param name="property"></param>
        /// <returns></returns>
        public static SetValueExecutor CompileSetValueExecutor(PropertyInfo property)
        {
            if (!property.CanWrite) return null;

            MethodInfo setMethodInfo = property.GetSetMethod();

            ParameterExpression instanceParameter = Expression.Parameter(typeof(object), "instance");
            ParameterExpression valueParameter = Expression.Parameter(typeof(object), "value");

            UnaryExpression valueCast = Expression.Convert(valueParameter, property.PropertyType);
            UnaryExpression instanceCast = (!setMethodInfo.IsStatic) ? Expression.Convert(instanceParameter, property.ReflectedType) : null;

            MethodCallExpression methodCall = Expression.Call(instanceCast, setMethodInfo, valueCast);

            Expression<SetValueExecutor> setValueExecutor = Expression.Lambda<SetValueExecutor>(methodCall, instanceParameter, valueParameter);

            return setValueExecutor.Compile();
        }

        /// <summary>
        /// 编译获取属性值表达式
        /// </summary>
        /// <param name="property"></param>
        /// <returns></returns>
        public static GetValueExecutor CompileGetValueExecutor(PropertyInfo property)
        {
            if (!property.CanRead) return null;

            MethodInfo getMethodInfo = property.GetGetMethod();

            ParameterExpression instanceParameter = Expression.Parameter(typeof(object), "instance");

            UnaryExpression instanceCast = (!getMethodInfo.IsStatic) ? Expression.Convert(instanceParameter, property.ReflectedType) : null;

            MethodCallExpression methodCall = Expression.Call(instanceCast, getMethodInfo);

            UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));

            Expression<GetValueExecutor> getValueExecutor = Expression.Lambda<GetValueExecutor>(castMethodCall, instanceParameter);

            return getValueExecutor.Compile();
        }
    }
}
